package org.fujene.memman;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Logger;

import org.fujene.communicate.blockwise.BlockwisePeerSystem;
import org.fujene.memcon.BlockwiseIndexMemory;
import org.fujene.memcon.IndexDisk;
import org.fujene.structure.Constants;
import org.fujene.structure.ContentInfo;
import org.fujene.structure.DataMatchingException;
import org.fujene.structure.ExtendQueue;
import org.fujene.structure.ExtendResult;
import org.fujene.structure.ExtendTerm;
import org.fujene.structure.LookupPointer;
import org.fujene.structure.SearchQueue;
import org.fujene.structure.Term;
import org.fujene.structure.TermList;
import org.fujene.term.Chopper;
import org.fujene.toolbox.ByteConverter;

public class BlockwiseMemoryManager {
	// ネットワークを利用する向けのインデックスシステムを分離
	private static final int DIGLENGTH = Constants.SKIPPTR_INTERVAL;

	// メモリ・ディスク本体
	private BlockwiseIndexMemory memory = null;
	private IndexDisk disk = null;

	public boolean stopFlag = false;

	private int indexcounter = 0;
	private int termcounter = 0;
	private int searchcounter = 0;

	public ContentInfo contentInfo = null;
	private BlockwisePeerSystem peer = null;
	public Logger logger = null;

	public BlockwiseMemoryManager(int blockSize, int blockLines,
			String dirPath, Logger logger, ContentInfo contentInfo,
			BlockwisePeerSystem peerSystem) {
		this.disk = new IndexDisk(dirPath);
		this.contentInfo = contentInfo;
		this.peer = peerSystem;
		this.memory = new BlockwiseIndexMemory(blockSize, blockLines, disk,
				contentInfo, logger, this);
		this.logger = logger;

		logger.fine("Memory manager started.");
	}

	public void index(ExtendQueue newIndex, Chopper chopper) {
		LookupPointer[] suppPtrs = new LookupPointer[newIndex.supplement_types];
		LookupPointer[] conPtrs = new LookupPointer[newIndex.content_types];
		int i;
		for (i = 0; i < newIndex.supplement_types; i++) {
			// 付加情報を格納
			suppPtrs[i] = storePureContent(newIndex.supplements[i], i);
		}

		for (i = 0; i < newIndex.content_types; i++) {
			conPtrs[i] = storeContent(newIndex.contents[i],
					contentInfo.constructIndex(suppPtrs, i), newIndex.ID, i);
		}

		for (i = 0; i < newIndex.content_types; i++) {
			// 形態素解析
			TermList terms = chopper.chop(newIndex.contents[i]);

			ExtendTerm newDic;
			// 2. 辞書あるか調べる
			for (Term term : terms) {
				// 3. 辞書しまう(あれば追加しない)
				try {
					newDic = storeDictionary(term.str(), i);
					for (int j = 0; j < newIndex.content_types; j++) {
						// 4. DocIDリストしまう
						storeInvIndex(newDic.ptr, conPtrs[i], term.freq(), j,
								j == 0);
					}

				} catch (UnsupportedEncodingException e) {
				}
			}
		}
		this.indexcounter++;
		if (this.indexcounter % 30000 == 0)
			System.gc();
	}

	// 検索
	public ExtendResult search(SearchQueue newQuery, Chopper chopper)
			throws UnsupportedEncodingException {
		long time = System.nanoTime();
		// 1-1. 形態素解析
		TermList rawTerms = chopper.chop(newQuery.query);
		int searchType = contentInfo.getContentIndex(newQuery.typestr);
		if (searchType == -1)
			return new ExtendResult(contentInfo);

		// クエリが2文字以上なら1文字だけは検索しない
		TermList terms = null;
		// if (newQuery.query.length() > 1) {
		// terms = new HashSet<String>(rawTerms.size());
		// for (String str : rawTerms) {
		// if (str.length() != 1)
		// terms.add(str);
		// }
		// } else {
		terms = rawTerms;
		// }

		logger.finest("Chop\t\t: " + ((System.nanoTime() - time) / 1000.0)
				+ " microsec.");
		// 暫定的に10単語で打ち切り
		ExtendTerm[] newDics = new ExtendTerm[(terms.size() > 10 ? 10 : terms
				.size())];
		boolean isZeroResult = false;

		int counter = 0;
		for (Term term : terms) {
			// クエリが2文字以上→1文字の単語は検索しない
			// 1. 辞書みる
			time = System.nanoTime();
			newDics[counter] = lookupTerm(term.str());

			logger.finest("Lookup " + (counter + 1) + "\t: "
					+ ((System.nanoTime() - time) / 1000.0) + " microsec.");
			time = System.nanoTime();
			if (newDics[counter].ptr == null) {
				// 辞書にない！ -> 終了
				isZeroResult = true;
				break;
			}
			for (int i = 0; i < newDics[counter].content_types; i++) {
				newDics[counter].invIndex[i] = getInvIndex(
						newDics[counter].ptr, i);
				logger.finest("Get ptr. " + (counter + 1) + "\t: "
						+ ((System.nanoTime() - time) / 1000.0) + " microsec.");

				time = System.nanoTime();
				if (newDics[counter].invIndex[i] == null) {
					isZeroResult = true;
					break;
				}
			}
			logger.finest("Cont. List " + (counter + 1) + "\t: "
					+ ((System.nanoTime() - time) / 1000.0) + " microsec.");

			if (++counter >= 10 || isZeroResult)
				break;
		}
		time = System.nanoTime();

		// 最後にインターセクション
		@SuppressWarnings("unchecked")
		ArrayList<LookupPointer>[] finalPtrLists = new ArrayList[contentInfo
				.getContentNum()];
		@SuppressWarnings("unchecked")
		ArrayList<LookupPointer>[] suppLists = new ArrayList[contentInfo
				.getSupplementNum()];
		for (int i = 0; i < contentInfo.getContentNum(); i++) {
			if (!isZeroResult) {
				if (counter > 1)
					finalPtrLists[i] = intersection(newDics, newQuery.length, i);
				else if (counter == 1)
					finalPtrLists[i] = getContentList(newDics[0].ptr,
							newQuery.from, newQuery.length, i);
			}
		}
		for (int i = 0; i < contentInfo.getSupplementNum(); i++) {
			suppLists[i] = getSupplementList(finalPtrLists[0], newQuery.from,
					newQuery.length, i);
		}

		logger.finest("Intersection\t: "
				+ ((System.nanoTime() - time) / 1000.0) + " microsec.");

		// 内容いくつか出す
		time = System.nanoTime();
		logger.finest("Content\t\t: " + ((System.nanoTime() - time) / 1000.0)
				+ " microsec.");

		if (finalPtrLists[0] != null)
			logger.finer("Result: " + finalPtrLists[0].size() + " articles.");
		else
			logger.finer("Result: 0 articles.");

		this.searchcounter++;

		return getContentsArray(finalPtrLists, suppLists, newQuery.from,
				newQuery.length);
	}

	public ExtendQueue lookupContent(LookupPointer[] ptrs, int priorIndex) {
		LookupPointer[] priorSupps = null;
		String[] strs = new String[ptrs.length];
		String[] supps = null;

		for (int i = 0; i < ptrs.length; i++) {
			strs[i] = memory.lookupContents(ptrs[i]);
			if (priorIndex == i)
				priorSupps = memory.lookupContentPurePointer(ptrs[i]);
		}
		supps = new String[priorSupps.length];
		for (int i = 0; i < supps.length; i++) {
			supps[i] = memory.lookupPureContent(priorSupps[i]);
		}

		return new ExtendQueue(strs, supps, 0);
	}

	public int getCounter() {
		try {
			return indexcounter;
		} catch (Exception e) {
			return -1;
		}
	}

	public int getTerms() {
		try {
			return termcounter;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	public int getSearchcounter() {
		return searchcounter;
	}

	public void getMemoryList() {
		memory.showMemoryElapsed();
	}

	public void initializeMemory() {
		try {
			memory.readMemory();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void saveMemory() {
		memory.saveMemories();
	}

	public int getSkipPointerLen() {
		return memory.getSkipPointerLength();
	}

	private ExtendTerm lookupTerm(String query) {
		// スキップポインタを見る
		int skipPointerLength = memory.getSkipPointerLength();
		LookupPointer dicPtr = null;
		LookupPointer nextPtr = null;
		ExtendTerm storedTerm = null;
		ExtendTerm returnTerm = null;
		int i;
		int skipLevel = 0;
		int skipVal = 1;
		if (skipPointerLength > 1) {
			skipLevel = (int) (Math.log(skipPointerLength - 1) / Math
					.log(DIGLENGTH));
			skipVal = (int) Math.pow(DIGLENGTH, skipLevel);
		}

		for (i = 0; i < skipPointerLength; i += skipVal) {
			dicPtr = memory.lookupSkipPointer(i);
			// ポインタなし
			if (dicPtr == null)
				break;

			storedTerm = memory.lookupDictionary(dicPtr);
			storedTerm.skipptr_index = i;
			int comp = storedTerm.term.compareTo(query);
			if (comp > 0) {
				// storeしてるほうが上 -> これより前
				skipLevel--;
				if (skipLevel == -1 || i == 0) {
					i--;
					break;
				}
				i -= skipVal;
				skipVal = (int) Math.pow(DIGLENGTH, skipLevel);

			} else if (comp == 0) {
				// まさにこの単語
				return storedTerm;
			}

			// 後ろを見る
			if (i + skipVal >= skipPointerLength) {
				do {
					skipLevel--;
					if (skipLevel == -1) {
						skipVal = 1;
						break;
					}
					skipVal = (int) Math.pow(DIGLENGTH, skipLevel);
				} while (i + skipVal >= skipPointerLength);
			}
		}
		if (i == -1) {
			// 一番先頭！ -> storedTermに意味はなくなる
			// 次の単語
			nextPtr = storedTerm.ptr;
			storedTerm = null;
		} else {
			// もう一度スキップポインタ取り出し
			if (i == skipPointerLength)
				i--;
			dicPtr = memory.lookupSkipPointer(i);
			storedTerm = memory.lookupDictionary(dicPtr);
		}

		// 辞書順検索
		if (storedTerm != null) {
			LookupPointer prevPtr = storedTerm.ptr;
			ExtendTerm nextTerm = memory.lookupDictionary(storedTerm.next);
			int count = 0;
			while (nextTerm != null) {
				int comp = nextTerm.term.compareTo(query);
				if (comp > 0) {
					// nextTermが上 -> 辞書になかった
					boolean addSkipPtr = count >= DIGLENGTH ? true : false;
					returnTerm = new ExtendTerm(query, null, prevPtr,
							nextTerm.ptr, i, addSkipPtr);
					break;
				} else if (comp == 0) {
					// ↓はいらないかも
					nextTerm.prev = prevPtr;
					return nextTerm;
				} else {
					prevPtr = nextTerm.ptr;
					nextTerm = memory.lookupDictionary(nextTerm.next);
				}
				count++;
			}

			if (returnTerm == null) {
				// 最後の単語だった
				boolean addSkipPtr = count >= DIGLENGTH ? true : false;
				returnTerm = new ExtendTerm(query, null, prevPtr, null, i,
						addSkipPtr);
			}
		} else {
			// 一番先頭(i = -1) or 最初の単語(i = 0)
			returnTerm = new ExtendTerm(query, null, null, nextPtr, i, false);
		}

		return returnTerm;
	}

	// 転置インデックスの「先頭」を取り出す
	private LookupPointer getInvIndex(LookupPointer dicPtr, int index) {
		return memory.lookupDictionaryInvIndex(dicPtr, index);
	}

	private void makeSkipPtr(ExtendTerm term) {
		int index = term.skipptr_index;

		if (index == -1) {
			// 最初の部分書き換え
			memory.storeSkipPointer(0, term.ptr, true);
			refreshSkipPtr();
		} else {
			if (term.needSkipPtr) {
				// 追加
				memory.storeSkipPointer(index + 1, term.ptr, false);
			}
		}
	}

	// 1番目のスキップポインタに固まらない対策
	private void refreshSkipPtr() {
		LookupPointer threshold = memory.lookupSkipPointer(1);
		LookupPointer nextPtr = memory.lookupSkipPointer(0);
		LookupPointer prevPtr = null;
		int count = 0;
		if (threshold == null) {
			while (nextPtr != null) {
				prevPtr = nextPtr;
				nextPtr = memory.lookupDictionaryNext(nextPtr);
				count++;
			}
		} else {
			while (threshold.equals(nextPtr)) {
				prevPtr = nextPtr;
				nextPtr = memory.lookupDictionaryNext(nextPtr);
				count++;
			}
		}

		if (count >= DIGLENGTH) {
			memory.storeSkipPointer(1, prevPtr, false);
		}
	}

	// 辞書をストア
	private ExtendTerm storeDictionary(String query, int valueType)
			throws UnsupportedEncodingException {
		ExtendTerm newTerm = lookupTerm(query);

		if (newTerm.ptr == null) {
			// 単語追加
			LookupPointer newTermPtr = memory.storeDictionary(newTerm.term,
					newTerm.next);
			newTerm.ptr = newTermPtr;

			// ポインタ接続
			if (newTerm.prev != null)
				memory.storeDictionaryPointer(newTerm.prev, newTermPtr);

			// スキップポインタ追加
			makeSkipPtr(newTerm);

			this.termcounter++;
		}

		return newTerm;
	}

	private void storeInvIndex(LookupPointer dicPtr, LookupPointer contentPtr,
			int termfreq, int valueType, boolean isIncrement) {
		// 転置インデックスのポインタ取得
		LookupPointer prevPtr = memory.lookupDictionaryInvIndex(dicPtr,
				valueType);

		// 転置インデックス書き込み
		LookupPointer invIndexPtr = memory.storeInvertIndex(prevPtr,
				contentPtr, termfreq);

		// 辞書ポインタ更新
		memory.storeDictionaryToInvIndex(dicPtr, invIndexPtr, valueType,
				isIncrement);
	}

	// 本文をメモリにストア
	public LookupPointer storeContent(String content,
			LookupPointer[] pureContent, long ID, int index) {
		return memory.storeContents(content, pureContent, ID, index);
	}

	// 本文をメモリにストア
	public LookupPointer storePureContent(String content, int index) {
		return memory.storePureContent(content, index);
	}

	// 削除DocIDを追加
	public void deleteContent(long ID, int index) {
		// ContentIDs infos = lookupContentPointerExtent(ID, index);
		// if (infos.currentPtr != null) {
		// TODO: 削除操作
		// }
	}

	private ArrayList<LookupPointer> getContentList(LookupPointer dicPtr,
			int from, int len, int type) {
		ArrayList<LookupPointer> result = new ArrayList<LookupPointer>(len);

		LookupPointer invIndexPtr = memory.lookupDictionaryInvIndex(dicPtr,
				type);
		LookupPointer eachPtrs = null;
		int counter = 0;
		while (invIndexPtr != null) {
			eachPtrs = memory.lookupInvIndexContentPtr(invIndexPtr);
			if (counter >= from && eachPtrs != null)
				result.add(eachPtrs);

			invIndexPtr = memory.lookupNextInvIndex(invIndexPtr);
			if (++counter >= from + len)
				break;
		}

		return result;
	}

	private ArrayList<LookupPointer> getSupplementList(
			ArrayList<LookupPointer> contentPtr, int from, int len, int type) {
		ArrayList<LookupPointer> result = new ArrayList<LookupPointer>(len);
		LookupPointer[] purePtrs;

		for (LookupPointer eachContent : contentPtr) {
			purePtrs = memory.lookupContentPurePointer(eachContent);
			result.add(purePtrs[type]);
		}

		return result;
	}

	// 多重インターセクション
	private ArrayList<LookupPointer> intersection(ExtendTerm[] extTerm,
			int length, int typeIndex) {
		try {
			ArrayList<LookupPointer> finalPtr = new ArrayList<LookupPointer>(
					length + 1);

			int ptrlen = extTerm.length;
			LookupPointer[] currentPtrs = new LookupPointer[ptrlen];
			LookupPointer[] prevPtrs = new LookupPointer[ptrlen];
			int counter = 0;
			boolean samePtr = false;
			boolean isDone = false;
			int newestIndex;
			LookupPointer newestPtr;
			int comps;

			// 計算量: O(n)
			for (int i = 0; i < ptrlen; i++) {
				currentPtrs[i] = memory
						.lookupInvIndexContentPtr(extTerm[i].invIndex[typeIndex]);
				prevPtrs[i] = memory
						.lookupNextInvIndex(extTerm[i].invIndex[typeIndex]);
			}

			while (counter < length) {
				samePtr = true;
				newestIndex = 0;
				newestPtr = currentPtrs[0];
				// ポインタの比較
				for (int i = 1; i < ptrlen; i++) {
					comps = newestPtr.compareTo(currentPtrs[i]);
					if (comps < 0) {
						newestIndex = i;
						newestPtr = currentPtrs[i];
						samePtr = false;
					} else if (samePtr && comps > 0) {
						samePtr = false;
					}
				}

				if (samePtr) {
					// 一致 全ポインタ進め
					finalPtr.add(newestPtr);
					counter++;
					for (int i = 0; i < ptrlen; i++) {
						if (prevPtrs[i] == null) {
							// もう進めない！
							isDone = true;
							break;
						}
						currentPtrs[i] = memory
								.lookupInvIndexContentPtr(prevPtrs[i]);
						prevPtrs[i] = memory.lookupNextInvIndex(prevPtrs[i]);
					}
				} else {
					// 一番新しいものを進める
					if (prevPtrs[newestIndex] != null) {
						currentPtrs[newestIndex] = memory
								.lookupInvIndexContentPtr(prevPtrs[newestIndex]);
						prevPtrs[newestIndex] = memory
								.lookupNextInvIndex(prevPtrs[newestIndex]);
					} else {
						// これ以上揃いようがない
						isDone = true;
					}
				}

				if (isDone)
					break;
			}

			return finalPtr;
		} catch (Exception e) {

			e.printStackTrace();
			return null;
		}
	}

	// 本文を取得
	private ExtendResult getContentsArray(
			ArrayList<LookupPointer>[] contentPtr,
			ArrayList<LookupPointer>[] suppPtr, int from, int length) {
		assert contentPtr.length > 0;

		ExtendResult result = new ExtendResult(contentInfo);
		ExtendQueue[] queues = new ExtendQueue[(contentPtr[0] != null ? contentPtr[0]
				.size() : 0)];
		int i;

		for (i = 0; i < (queues.length < from + length ? queues.length : from
				+ length); i++) {
			queues[i] = new ExtendQueue(contentPtr.length, suppPtr.length, 0);

			for (int j = 0; j < contentPtr.length; j++) {
				queues[i].contents[j] = memory.lookupContents(contentPtr[j]
						.get(i));
			}

			for (int j = 0; j < suppPtr.length; j++) {
				queues[i].supplements[j] = memory.lookupPureContent(suppPtr[j]
						.get(i));
			}
		}
		result.setResult(queues);

		return result;
	}
	
	private ArrayList<LookupPointer> sortByScore(ArrayList<LookupPointer> ptrs){
		return ptrs;
	}

	public int getBlockType(int blockIndex) {
		try {
			return memory.getBlockType(blockIndex);
		} catch (Exception e) {
			return -1;
		}
	}

	public int getContentType(int blockIndex) {
		return memory.getContentType(blockIndex);
	}

	public byte[] getBlock(int blockIndex) {
		try {
			return memory.leftBlock(blockIndex);
		} catch (Exception e) {
			return null;
		}
	}
	
	public Integer[] getBlockList() {
		return memory.getBlockTypeList();
	}

	public void setBlock(byte[] blockData, int blockIndex, int blockType,
			int contentType) throws DataMatchingException, IOException {
		memory.joinBlock(blockData, blockIndex, blockType, contentType);
	}
	
	public void registerBlock(int blockIndex, int blockType, int contentIndex) {
		memory.registerBlock(blockIndex, blockType, contentIndex);
	}

	public void deleteBlock(int blockIndex) {
		memory.clearBlock(blockIndex);
	}

	// Get系関数はここにまとめる
	public byte[] callGetFunc(String func, int blockIndex, byte[] argbytes, boolean atOnce) {
		return peer.callGetFunc(func, blockIndex, argbytes, atOnce);
	}

	// Set系関数はここにまとめる
	public byte[] callSetFunc(String func, int blockIndex, byte[] argbytes, boolean atOnce) {
		return peer.callSetFunc(func, blockIndex, argbytes, atOnce);
	}

	public byte[] invokeGetFunc(String func, byte[] argbytes) {
		if (func.equals("lookupContents")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes);
			try {
				return memory.lookupContentsImpl(ptr).getBytes("UTF-8");
			} catch (UnsupportedEncodingException e) {
			}

		} else if (func.equals("lookupDictionary")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes);
			ExtendTerm term = memory.lookupDictionaryImpl(ptr);
			return term.createByteArray();

		} else if (func.equals("lookupDictionaryInvIndex")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes, 0);
			int index = ByteConverter.byteToInt(argbytes, 6, 4);
			return ByteConverter.setPtr(memory.lookupDictionaryInvIndexImpl(
					ptr, index));

		} else if (func.equals("lookupDictionaryNext")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes, 0);
			return ByteConverter.setPtr(memory.lookupDictionaryNextImpl(
					ptr));

		} else if (func.equals("lookupNextInvIndex")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes);
			LookupPointer retPtr = memory.lookupNextInvIndexImpl(ptr);
			return ByteConverter.setPtr(retPtr != null ? retPtr : Constants.emptyPointer);

		} else if (func.equals("lookupInvIndexContentPtr")) {
			LookupPointer ptr = ByteConverter.getPtr(argbytes);
			return ByteConverter.setPtr(memory.lookupInvIndexContentPtrImpl(ptr));

		} else if (func.equals("lookupPureContent")) {
			try {
				LookupPointer ptr = ByteConverter.getPtr(argbytes);
				return memory.lookupPureContentImpl(ptr).getBytes("UTF-8");
			} catch (UnsupportedEncodingException e) {
			}

		} else if (func.equals("lookupContentPurePointer")) {
			try {
				LookupPointer ptr = ByteConverter.getPtr(argbytes);
				LookupPointer[] values = memory
						.lookupContentPurePointerImpl(ptr);
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				stream.write(ByteConverter.intToByte(values.length, 2));
				for (int i = 0; i < values.length; i++) {
					stream.write(ByteConverter.setPtr(values[i]));
				}
				return stream.toByteArray();
			} catch (IOException e) {
			}

		} else if (func.equals("lookupSkipPointer")) {
			int index = ByteConverter.byteToInt(argbytes);
			return ByteConverter.setPtr(memory.lookupSkipPointerImpl(index));
			
		} else if (func.equals("getSkipPointerLength")) {
			return ByteConverter.intToByte(memory.getSkipPointerLengthImpl(), 4);
		}

		throw new NoSuchMethodError();
	}

	public byte[] invokeSetFunc(String func, byte[] argbytes) {
		if (func.equals("storeContents")) {
			try {
				int index = ByteConverter.byteToInt(argbytes, 0, 4);
				long ID = ByteConverter.byteToLong(argbytes, 4, 8);
				int ptrlen = ByteConverter.byteToInt(argbytes, 12, 2);
				LookupPointer[] ptrs = new LookupPointer[ptrlen];
				for (int i = 0; i < ptrs.length; i++) {
					ptrs[i] = ByteConverter.getPtr(argbytes, 14 + (6 * i));
				}
				String str = new String(Arrays.copyOfRange(argbytes,
						14 + (6 * ptrlen), argbytes.length), "UTF-8");
				return ByteConverter.setPtr(memory.storeContentsImpl(str, ptrs,
						ID, index));
			} catch (UnsupportedEncodingException e) {
			}

		} else if (func.equals("storeDictionary")) {
			try {
				LookupPointer ptr = ByteConverter.getPtr(argbytes, 0);
				String str = new String(Arrays.copyOfRange(argbytes, 6,
						argbytes.length), "UTF-8");
				return ByteConverter.setPtr(memory
						.storeDictionaryImpl(str, ptr));
			} catch (UnsupportedEncodingException e) {
			}

		} else if (func.equals("storeDictionaryPointer")) {
			LookupPointer dicPtr = ByteConverter.getPtr(argbytes, 0);
			LookupPointer next = ByteConverter.getPtr(argbytes, 6);
			memory.storeDictionaryPointerImpl(dicPtr, next);
			return new byte[0];

		} else if (func.equals("storeDictionaryToInvIndex")) {
			LookupPointer dicPtr = ByteConverter.getPtr(argbytes, 0);
			LookupPointer invIndex = ByteConverter.getPtr(argbytes, 6);
			int index = ByteConverter.byteToInt(argbytes, 12, 3);
			boolean isIncrement = argbytes[15] == 1 ? true : false;
			memory.storeDictionaryToInvIndexImpl(dicPtr, invIndex, index,
					isIncrement);
			return new byte[0];

		} else if (func.equals("storeInvertIndex")) {
			LookupPointer prev = ByteConverter.getPtr(argbytes, 0);
			LookupPointer ptr = ByteConverter.getPtr(argbytes, 6);
			int termfreq = ByteConverter.byteToInt(argbytes, 12, 2);
			return ByteConverter.setPtr(memory.storeInvertIndexImpl(prev, ptr,
					termfreq));

		} else if (func.equals("storePureContent")) {
			try {
				int index = ByteConverter.byteToInt(argbytes, 0, 3);
				String str = new String(Arrays.copyOfRange(argbytes, 6,
						argbytes.length), "UTF-8");
				return ByteConverter.setPtr(memory.storePureContentImpl(str,
						index));
			} catch (UnsupportedEncodingException e) {
			}

		} else if (func.equals("storeSkipPointer")) {
			int index = ByteConverter.byteToInt(argbytes, 0, 3);
			LookupPointer ptr = ByteConverter.getPtr(argbytes, 3);
			boolean isModify = (ByteConverter.byteToInt(argbytes, 9, 1) == 1 ? true
					: false);
			memory.storeSkipPointerImpl(index, ptr, isModify);
			return new byte[0];
		}

		throw new NoSuchMethodError();
	}

	public int getBlockAmount() {
		return memory.getBlockAmount();
	}

	public boolean existsLocal(int blockIndex) {
		return memory.existsLocal(blockIndex);
	}
	
	public boolean storeLocally(int blockIndex) {
		return peer.storeLocally(blockIndex);
	}

	public void pushBlock(int blockIndex, int blockType, int contentIndex,
			boolean isAllocate) {
		memory.pushBlock(blockIndex, blockType, contentIndex, isAllocate);
	}

	public void setBlock(int blockIndex, int blockType, int contentIndex) {
		peer.setBlock(blockIndex, blockType, contentIndex);
	}
}
